/*************************************************************************
	> File Name: trylock.c
	> Author: chen
	> Mail: chen_tmacy@foxmail.com
	> Created Time: 2015年01月04日 星期日 16时07分42秒
    > 计数线程 counter_thread 大约每隔1s会醒来一次，锁住互斥量，增加计数器
    >　的值。监控线程 monitor_thread 大约3s醒来一次，尝试锁住互斥量，若返回
    > EBUSY，则表示无法获取互斥量，再次睡眠3s。若成功锁住互斥量，则打印
    > 计数器的值
 ************************************************************************/

#include<pthread.h>
#include"errors.h"

#define SPIN 10000000

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int counter;
time_t end_time;

void *counter_thread(void* arg){
    int status;
    int spin;

    while(time(NULL) < end_time){
        if((status = pthread_mutex_lock(&mutex)) != 0){
            err_abort(status,"Lock mutex");
        }
        for(spin = 0;spin < SPIN;spin++)
            ;
        counter++;
        
        if( (status = pthread_mutex_unlock(&mutex)) != 0)
           err_abort(status,"Unlock mutex");
        sleep(1);
    }
    printf("Counter thread : Counter is %#d\n",counter);
    return NULL;
}


void* monitor_thread(void* arg){
    int status;
    int misses = 0;
    
    while(time(NULL) < end_time){
        sleep(3);
        status = pthread_mutex_trylock(&mutex);
        if(status != EBUSY){
            if(status){
               err_abort(status,"Trylock mutex"); 
            }
            printf("Counter is %d\n",counter);
            if(status = pthread_mutex_unlock(&mutex)){
                err_abort(status,"Unlock mutex");
            }
        }else
            misses++;
        printf("Monitor thread missed updata %d times.\n",misses);
    }
    return NULL;
}

int main(int argc,char *argv[]){
    int status;
    pthread_t counter_thread_id;
    pthread_t monitor_thread_id;

    end_time = time(NULL) + 60; // Run for 1 minute;
    if(status = pthread_create(&counter_thread_id,NULL,
                                counter_thread,NULL))
        err_abort(status,"Create counter thread");
    if(status = pthread_create(&monitor_thread_id,NULL,
                                monitor_thread,NULL))
        err_abort(status,"Create monitor thread");
    
    if(status = pthread_join(counter_thread_id,NULL))
        err_abort(status,"Join counter thread");

    if(status = pthread_join(monitor_thread_id,NULL))
        err_abort(status,"Join monitor thread");
    return 0;
}


